"""
Case Type   : 子事务并发回滚功能模块-5.1.0新增特性
Case Name   : 高并发子事务线程未提交或者回滚场景下，进行并发线程kill-2后，数据库功能正常
Create At   : 2024/1/24
Owner       : peilinqian
Description :
    1. 远程复制java脚本及jar包至指定路径;
    2. 编译java文件;
    3. 开始运行java程序;
    4. 等待所有子事务执行完成后rollback时，kill -2 java 进程;
    5. 再次运行java程序;
Expect      :
    1. 远程复制java脚本及jar包至指定路径; 复制成功
    2. 编译java文件; 编译成功
    3. 开始运行java程序; 开始运行
    4. 等待所有子事务执行完成后rollback时，kill -2 java 进程; 中断成功
    5. 再次运行java程序; 执行结果正确
History     :
"""
import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class TestCase(unittest.TestCase):

    def setUp(self):
        self.log = Logger()
        self.log.info("----this is setup----")
        self.log.info(f'----{os.path.basename(__file__)}:start----')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.pri_root = Node(node='PrimaryRoot')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.sta2_root = Node(node='Standby2Root')
        self.target_path = os.path.join(macro.DB_BACKUP_PATH,
                                        "Human_Subxact_Rollback_Case0002")
        self.java_name = "Human_Subxact_Rollback_Case0001"
        self.schema_name = 'schema_human_subxact_rollback_case0002'
        self.com = Common()
        self.constant = Constant()
        self.subxact_num = 3000  # 每个连接子事务数量
        self.time_before_rollback = 60  # 等待所有子事务执行完成后rollback前等待时间
        self.commit_con_num = 20  # commit的连接数
        self.rollback_con_num = 30  # rollback 的连接数
        self.java_output = os.path.join(self.target_path,
                                        self.java_name + '.output')

    def test_main(self):
        step_txt = '----step1:远程复制java脚本及jar包至指定路径; expect:复制成功----'
        self.log.info(step_txt)
        self.com.scp_file(self.sta2_root, f"{self.java_name}.java",
                          self.target_path)
        self.jar_name = self.com.get_jdbc('opengauss', self.target_path)
        self.log.info("--验证复制成功--")
        check_cmd = f'ls {self.target_path}'
        self.log.info(check_cmd)
        check_result = self.sta2_root.sh(check_cmd).result()
        self.log.info(check_result)
        self.assertIn(self.java_name, check_result, '执行失败' + step_txt)
        self.assertIn('opengauss', check_result, '执行失败' + step_txt)

        step_txt = '----step2:编译java文件; expect:编译成功----'
        self.log.info(step_txt)
        javac_cmd = f"javac -encoding utf-8 -cp " \
            f"{os.path.join(self.target_path, self.jar_name)} " \
            f"{os.path.join(self.target_path, f'{self.java_name}.java')}"
        self.log.info(javac_cmd)
        javac_result = self.sta2_root.sh(javac_cmd).result()
        self.log.info(javac_result)
        self.assertEqual('', javac_result, "执行失败" + step_txt)

        step_txt = '----step3:开始运行java程序; expect:开始运行----'
        self.log.info(step_txt)
        url_host_port = f"{self.pri_dbuser.db_host}:{self.pri_dbuser.db_port}"
        java_cmd = f"java -cp " \
            f"{os.path.join(self.target_path, self.jar_name)}" \
            f":{self.target_path} {self.java_name} " \
            f"{url_host_port} {self.pri_dbuser.db_name} " \
            f"{self.schema_name} {self.pri_dbuser.db_user} " \
            f"{self.pri_dbuser.db_password} {self.subxact_num} " \
            f"{self.time_before_rollback} {self.commit_con_num} " \
            f"{self.rollback_con_num} " \
            f"> {self.java_output}_1"
        java_thread = ComThread(self.com.get_sh_result,
                                args=(self.sta2_root, java_cmd))
        java_thread.setDaemon(True)
        java_thread.start()
        time.sleep(self.time_before_rollback)

        step_txt = '----step4:等待所有子事务执行完成后rollback时，kill -2 java 进程; ' \
                   'expect:中断成功----'
        self.log.info(step_txt)
        self.com.kill_pid_keyword(self.java_name, 2, self.sta2_root)
        java_thread.join(60)
        java_result = java_thread.get_result()
        self.log.info(java_result)
        self.log.info(self.java_output)
        check_cmd = f'cat {self.java_output}_1'
        self.log.info(check_cmd)
        check_result = self.sta2_root.sh(check_cmd).result()
        self.log.info(check_result)
        self.assertNotEqual(java_result.count('time interval'),
                            self.commit_con_num + self.rollback_con_num,
                            "执行失败" + step_txt)

        step_txt = '----step5:再次运行java程序; expect:执行结果正确----'
        self.log.info(step_txt)
        java_cmd = f"java -cp " \
            f"{os.path.join(self.target_path, self.jar_name)}" \
            f":{self.target_path} {self.java_name} " \
            f"{url_host_port} {self.pri_dbuser.db_name} " \
            f"{self.schema_name} {self.pri_dbuser.db_user} " \
            f"{self.pri_dbuser.db_password} {self.subxact_num} " \
            f"{self.time_before_rollback} {self.commit_con_num} " \
            f"{self.rollback_con_num} " \
            f"> {self.java_output}_2"
        self.log.info(java_cmd)
        java_result = self.sta2_root.sh(java_cmd).result()
        self.log.info(java_result)
        check_cmd = f'cat {self.java_output}_2'
        self.log.info(check_cmd)
        check_result = self.sta2_root.sh(check_cmd).result()
        self.log.info(check_result)
        self.assertNotEqual(java_result.count('time interval'),
                            self.commit_con_num + self.rollback_con_num,
                            "执行失败" + step_txt)
        self.suc_flag = (check_result.count(
            'time interval') == self.commit_con_num + self.rollback_con_num)
        self.assertEqual(check_result.count('time interval'),
                         self.commit_con_num + self.rollback_con_num,
                         "执行失败" + step_txt)

    def tearDown(self):
        self.log.info('----this is teardown----')
        if self.suc_flag:
            step_txt1 = '----删除数据; expect:删除成功----'
            self.log.info(step_txt1)
            drop_sql = f"drop schema if exists {self.schema_name} cascade;"
            drop_result = self.pri_sh.executDbSql(drop_sql)
            self.log.info(drop_result)
            step_txt2 = '----清理编译脚本; expect:清理成功----'
            self.log.info(step_txt2)
            file_rm_cmd = f'rm -rf {self.target_path};' \
                f'if [ -d {self.target_path} ]; ' \
                f'then echo "exists"; else echo "not exists"; fi'
            self.log.info(file_rm_cmd)
            file_rm_result = self.sta2_root.sh(file_rm_cmd).result()
            self.log.info(file_rm_result)

            self.log.info('----清理环境断言----')
            self.assertIn(self.constant.drop_schema_success_msg, drop_result,
                          '执行失败' + step_txt1)
            self.assertEqual('not exists', file_rm_result, "执行失败" + step_txt2)

        self.log.info(f'----{os.path.basename(__file__)}:end----')
